1 //===-- UnwindAssemblyInstEmulation.cpp -----------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 #include "UnwindAssemblyInstEmulation.h"
11 #include "lldb/Core/Address.h"
12 #include "lldb/Core/Disassembler.h"
13 #include "lldb/Core/DumpDataExtractor.h"
14 #include "lldb/Core/DumpRegisterValue.h"
15 #include "lldb/Core/FormatEntity.h"
16 #include "lldb/Core/PluginManager.h"
17 #include "lldb/Target/ExecutionContext.h"
18 #include "lldb/Target/Process.h"
19 #include "lldb/Target/Target.h"
20 #include "lldb/Target/Thread.h"
21 #include "lldb/Utility/ArchSpec.h"
22 #include "lldb/Utility/DataBufferHeap.h"
23 #include "lldb/Utility/DataExtractor.h"
24 #include "lldb/Utility/LLDBLog.h"
25 #include "lldb/Utility/Log.h"
26 #include "lldb/Utility/Status.h"
27 #include "lldb/Utility/StreamString.h"
30 using namespace lldb_private
;
32 LLDB_PLUGIN_DEFINE(UnwindAssemblyInstEmulation
)
34 // UnwindAssemblyInstEmulation method definitions
36 bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
37 AddressRange
&range
, Thread
&thread
, UnwindPlan
&unwind_plan
) {
38 std::vector
<uint8_t> function_text(range
.GetByteSize());
39 ProcessSP
process_sp(thread
.GetProcess());
42 const bool force_live_memory
= true;
43 if (process_sp
->GetTarget().ReadMemory(
44 range
.GetBaseAddress(), function_text
.data(), range
.GetByteSize(),
45 error
, force_live_memory
) != range
.GetByteSize()) {
49 return GetNonCallSiteUnwindPlanFromAssembly(
50 range
, function_text
.data(), function_text
.size(), unwind_plan
);
53 bool UnwindAssemblyInstEmulation::GetNonCallSiteUnwindPlanFromAssembly(
54 AddressRange
&range
, uint8_t *opcode_data
, size_t opcode_size
,
55 UnwindPlan
&unwind_plan
) {
56 if (opcode_data
== nullptr || opcode_size
== 0)
59 if (range
.GetByteSize() > 0 && range
.GetBaseAddress().IsValid() &&
60 m_inst_emulator_up
.get()) {
62 // The instruction emulation subclass setup the unwind plan for the first
64 m_inst_emulator_up
->CreateFunctionEntryUnwind(unwind_plan
);
66 // CreateFunctionEntryUnwind should have created the first row. If it
67 // doesn't, then we are done.
68 if (unwind_plan
.GetRowCount() == 0)
71 const bool prefer_file_cache
= true;
72 DisassemblerSP
disasm_sp(Disassembler::DisassembleBytes(
73 m_arch
, nullptr, nullptr, nullptr, nullptr, range
.GetBaseAddress(),
74 opcode_data
, opcode_size
, 99999, prefer_file_cache
));
76 Log
*log
= GetLog(LLDBLog::Unwind
);
81 m_unwind_plan_ptr
= &unwind_plan
;
83 const uint32_t addr_byte_size
= m_arch
.GetAddressByteSize();
84 const bool show_address
= true;
85 const bool show_bytes
= true;
86 const bool show_control_flow_kind
= false;
87 m_cfa_reg_info
= *m_inst_emulator_up
->GetRegisterInfo(
88 unwind_plan
.GetRegisterKind(), unwind_plan
.GetInitialCFARegister());
90 m_register_values
.clear();
91 m_pushed_regs
.clear();
93 // Initialize the CFA with a known value. In the 32 bit case it will be
94 // 0x80000000, and in the 64 bit case 0x8000000000000000. We use the
95 // 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
);
101 const InstructionList
&inst_list
= disasm_sp
->GetInstructionList();
102 const size_t num_instructions
= inst_list
.GetSize();
104 if (num_instructions
> 0) {
105 Instruction
*inst
= inst_list
.GetInstructionAtIndex(0).get();
106 const lldb::addr_t base_addr
= inst
->GetAddress().GetFileAddress();
108 // Map for storing the unwind plan row and the value of the registers
109 // at a given offset. When we see a forward branch we add a new entry
110 // to this map with the actual unwind plan row and register context for
111 // the target address of the branch as the current data have to be
112 // valid for the target address of the branch too if we are in the same
114 std::map
<lldb::addr_t
, std::pair
<UnwindPlan::RowSP
, RegisterValueMap
>>
117 // Make a copy of the current instruction Row and save it in m_curr_row
118 // so we can add updates as we process the instructions.
119 UnwindPlan::RowSP last_row
= unwind_plan
.GetLastRow();
120 UnwindPlan::Row
*newrow
= new UnwindPlan::Row
;
122 *newrow
= *last_row
.get();
123 m_curr_row
.reset(newrow
);
125 // Add the initial state to the save list with offset 0.
126 saved_unwind_states
.insert({0, {last_row
, m_register_values
}});
128 // cache the stack pointer register number (in whatever register
129 // numbering this UnwindPlan uses) for quick reference during
130 // instruction parsing.
131 RegisterInfo sp_reg_info
= *m_inst_emulator_up
->GetRegisterInfo(
132 eRegisterKindGeneric
, LLDB_REGNUM_GENERIC_SP
);
134 // The architecture dependent condition code of the last processed
136 EmulateInstruction::InstructionCondition last_condition
=
137 EmulateInstruction::UnconditionalCondition
;
138 lldb::addr_t condition_block_start_offset
= 0;
140 for (size_t idx
= 0; idx
< num_instructions
; ++idx
) {
141 m_curr_row_modified
= false;
142 m_forward_branch_offset
= 0;
144 inst
= inst_list
.GetInstructionAtIndex(idx
).get();
146 lldb::addr_t current_offset
=
147 inst
->GetAddress().GetFileAddress() - base_addr
;
148 auto it
= saved_unwind_states
.upper_bound(current_offset
);
149 assert(it
!= saved_unwind_states
.begin() &&
150 "Unwind row for the function entry missing");
151 --it
; // Move it to the row corresponding to the current offset
153 // If the offset of m_curr_row don't match with the offset we see
154 // in saved_unwind_states then we have to update m_curr_row and
155 // m_register_values based on the saved values. It is happening
156 // after we processed an epilogue and a return to caller
158 if (it
->second
.first
->GetOffset() != m_curr_row
->GetOffset()) {
159 UnwindPlan::Row
*newrow
= new UnwindPlan::Row
;
160 *newrow
= *it
->second
.first
;
161 m_curr_row
.reset(newrow
);
162 m_register_values
= it
->second
.second
;
163 // re-set the CFA register ivars to match the
165 if (sp_reg_info
.name
&&
166 m_curr_row
->GetCFAValue().IsRegisterPlusOffset()) {
167 uint32_t row_cfa_regnum
=
168 m_curr_row
->GetCFAValue().GetRegisterNumber();
169 lldb::RegisterKind row_kind
=
170 m_unwind_plan_ptr
->GetRegisterKind();
171 // set m_cfa_reg_info to the row's CFA reg.
172 m_cfa_reg_info
= *m_inst_emulator_up
->GetRegisterInfo(
173 row_kind
, row_cfa_regnum
);
175 if (sp_reg_info
.kinds
[row_kind
] == row_cfa_regnum
)
182 m_inst_emulator_up
->SetInstruction(inst
->GetOpcode(),
183 inst
->GetAddress(), nullptr);
185 if (last_condition
!=
186 m_inst_emulator_up
->GetInstructionCondition()) {
187 if (m_inst_emulator_up
->GetInstructionCondition() !=
188 EmulateInstruction::UnconditionalCondition
&&
189 saved_unwind_states
.count(current_offset
) == 0) {
190 // If we don't have a saved row for the current offset then
191 // save our current state because we will have to restore it
192 // after the conditional block.
194 std::make_shared
<UnwindPlan::Row
>(*m_curr_row
.get());
195 saved_unwind_states
.insert(
196 {current_offset
, {new_row
, m_register_values
}});
199 // If the last instruction was conditional with a different
200 // condition then the then current condition then restore the
202 if (last_condition
!=
203 EmulateInstruction::UnconditionalCondition
) {
204 const auto &saved_state
=
205 saved_unwind_states
.at(condition_block_start_offset
);
207 std::make_shared
<UnwindPlan::Row
>(*saved_state
.first
);
208 m_curr_row
->SetOffset(current_offset
);
209 m_register_values
= saved_state
.second
;
210 // re-set the CFA register ivars to match the
212 if (sp_reg_info
.name
&&
213 m_curr_row
->GetCFAValue().IsRegisterPlusOffset()) {
214 uint32_t row_cfa_regnum
=
215 m_curr_row
->GetCFAValue().GetRegisterNumber();
216 lldb::RegisterKind row_kind
=
217 m_unwind_plan_ptr
->GetRegisterKind();
218 // set m_cfa_reg_info to the row's CFA reg.
219 m_cfa_reg_info
= *m_inst_emulator_up
->GetRegisterInfo(
220 row_kind
, row_cfa_regnum
);
222 if (sp_reg_info
.kinds
[row_kind
] == row_cfa_regnum
)
227 bool replace_existing
=
228 true; // The last instruction might already
229 // created a row for this offset and
230 // we want to overwrite it.
231 unwind_plan
.InsertRow(
232 std::make_shared
<UnwindPlan::Row
>(*m_curr_row
),
236 // We are starting a new conditional block at the actual offset
237 condition_block_start_offset
= current_offset
;
240 if (log
&& log
->GetVerbose()) {
242 lldb_private::FormatEntity::Entry format
;
243 FormatEntity::Parse("${frame.pc}: ", format
);
244 inst
->Dump(&strm
, inst_list
.GetMaxOpcocdeByteSize(), show_address
,
245 show_bytes
, show_control_flow_kind
, nullptr, nullptr,
246 nullptr, &format
, 0);
247 log
->PutString(strm
.GetString());
250 last_condition
= m_inst_emulator_up
->GetInstructionCondition();
252 m_inst_emulator_up
->EvaluateInstruction(
253 eEmulateInstructionOptionIgnoreConditions
);
255 // If the current instruction is a branch forward then save the
256 // current CFI information for the offset where we are branching.
257 if (m_forward_branch_offset
!= 0 &&
258 range
.ContainsFileAddress(inst
->GetAddress().GetFileAddress() +
259 m_forward_branch_offset
)) {
261 std::make_shared
<UnwindPlan::Row
>(*m_curr_row
.get());
262 newrow
->SetOffset(current_offset
+ m_forward_branch_offset
);
263 saved_unwind_states
.insert(
264 {current_offset
+ m_forward_branch_offset
,
265 {newrow
, m_register_values
}});
266 unwind_plan
.InsertRow(newrow
);
269 // Were there any changes to the CFI while evaluating this
271 if (m_curr_row_modified
) {
272 // Save the modified row if we don't already have a CFI row in
273 // the current address
274 if (saved_unwind_states
.count(
275 current_offset
+ inst
->GetOpcode().GetByteSize()) == 0) {
276 m_curr_row
->SetOffset(current_offset
+
277 inst
->GetOpcode().GetByteSize());
278 unwind_plan
.InsertRow(m_curr_row
);
279 saved_unwind_states
.insert(
280 {current_offset
+ inst
->GetOpcode().GetByteSize(),
281 {m_curr_row
, m_register_values
}});
283 // Allocate a new Row for m_curr_row, copy the current state
285 UnwindPlan::Row
*newrow
= new UnwindPlan::Row
;
286 *newrow
= *m_curr_row
.get();
287 m_curr_row
.reset(newrow
);
295 if (log
&& log
->GetVerbose()) {
297 lldb::addr_t base_addr
= range
.GetBaseAddress().GetFileAddress();
298 strm
.Printf("Resulting unwind rows for [0x%" PRIx64
" - 0x%" PRIx64
"):",
299 base_addr
, base_addr
+ range
.GetByteSize());
300 unwind_plan
.Dump(strm
, nullptr, base_addr
);
301 log
->PutString(strm
.GetString());
303 return unwind_plan
.GetRowCount() > 0;
308 bool UnwindAssemblyInstEmulation::AugmentUnwindPlanFromCallSite(
309 AddressRange
&func
, Thread
&thread
, UnwindPlan
&unwind_plan
) {
313 bool UnwindAssemblyInstEmulation::GetFastUnwindPlan(AddressRange
&func
,
315 UnwindPlan
&unwind_plan
) {
319 bool UnwindAssemblyInstEmulation::FirstNonPrologueInsn(
320 AddressRange
&func
, const ExecutionContext
&exe_ctx
,
321 Address
&first_non_prologue_insn
) {
326 UnwindAssemblyInstEmulation::CreateInstance(const ArchSpec
&arch
) {
327 std::unique_ptr
<EmulateInstruction
> inst_emulator_up(
328 EmulateInstruction::FindPlugin(arch
, eInstructionTypePrologueEpilogue
,
330 // Make sure that all prologue instructions are handled
331 if (inst_emulator_up
)
332 return new UnwindAssemblyInstEmulation(arch
, inst_emulator_up
.release());
336 void UnwindAssemblyInstEmulation::Initialize() {
337 PluginManager::RegisterPlugin(GetPluginNameStatic(),
338 GetPluginDescriptionStatic(), CreateInstance
);
341 void UnwindAssemblyInstEmulation::Terminate() {
342 PluginManager::UnregisterPlugin(CreateInstance
);
345 llvm::StringRef
UnwindAssemblyInstEmulation::GetPluginDescriptionStatic() {
346 return "Instruction emulation based unwind information.";
349 uint64_t UnwindAssemblyInstEmulation::MakeRegisterKindValuePair(
350 const RegisterInfo
®_info
) {
351 lldb::RegisterKind reg_kind
;
353 if (EmulateInstruction::GetBestRegisterKindAndNumber(®_info
, reg_kind
,
355 return (uint64_t)reg_kind
<< 24 | reg_num
;
359 void UnwindAssemblyInstEmulation::SetRegisterValue(
360 const RegisterInfo
®_info
, const RegisterValue
®_value
) {
361 m_register_values
[MakeRegisterKindValuePair(reg_info
)] = reg_value
;
364 bool UnwindAssemblyInstEmulation::GetRegisterValue(const RegisterInfo
®_info
,
365 RegisterValue
®_value
) {
366 const uint64_t reg_id
= MakeRegisterKindValuePair(reg_info
);
367 RegisterValueMap::const_iterator pos
= m_register_values
.find(reg_id
);
368 if (pos
!= m_register_values
.end()) {
369 reg_value
= pos
->second
;
370 return true; // We had a real value that comes from an opcode that wrote
373 // We are making up a value that is recognizable...
374 reg_value
.SetUInt(reg_id
, reg_info
.byte_size
);
378 size_t UnwindAssemblyInstEmulation::ReadMemory(
379 EmulateInstruction
*instruction
, void *baton
,
380 const EmulateInstruction::Context
&context
, lldb::addr_t addr
, void *dst
,
382 Log
*log
= GetLog(LLDBLog::Unwind
);
384 if (log
&& log
->GetVerbose()) {
387 "UnwindAssemblyInstEmulation::ReadMemory (addr = 0x%16.16" PRIx64
388 ", dst = %p, dst_len = %" PRIu64
", context = ",
389 addr
, dst
, (uint64_t)dst_len
);
390 context
.Dump(strm
, instruction
);
391 log
->PutString(strm
.GetString());
393 memset(dst
, 0, dst_len
);
397 size_t UnwindAssemblyInstEmulation::WriteMemory(
398 EmulateInstruction
*instruction
, void *baton
,
399 const EmulateInstruction::Context
&context
, lldb::addr_t addr
,
400 const void *dst
, size_t dst_len
) {
401 if (baton
&& dst
&& dst_len
)
402 return ((UnwindAssemblyInstEmulation
*)baton
)
403 ->WriteMemory(instruction
, context
, addr
, dst
, dst_len
);
407 size_t UnwindAssemblyInstEmulation::WriteMemory(
408 EmulateInstruction
*instruction
, const EmulateInstruction::Context
&context
,
409 lldb::addr_t addr
, const void *dst
, size_t dst_len
) {
410 DataExtractor
data(dst
, dst_len
,
411 instruction
->GetArchitecture().GetByteOrder(),
412 instruction
->GetArchitecture().GetAddressByteSize());
414 Log
*log
= GetLog(LLDBLog::Unwind
);
416 if (log
&& log
->GetVerbose()) {
419 strm
.PutCString("UnwindAssemblyInstEmulation::WriteMemory (");
420 DumpDataExtractor(data
, &strm
, 0, eFormatBytes
, 1, dst_len
, UINT32_MAX
,
422 strm
.PutCString(", context = ");
423 context
.Dump(strm
, instruction
);
424 log
->PutString(strm
.GetString());
427 switch (context
.type
) {
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
:
450 case EmulateInstruction::eContextPushRegisterOnStack
: {
451 uint32_t reg_num
= LLDB_INVALID_REGNUM
;
452 uint32_t generic_regnum
= LLDB_INVALID_REGNUM
;
453 assert(context
.GetInfoType() ==
454 EmulateInstruction::eInfoTypeRegisterToRegisterPlusOffset
&&
455 "unhandled case, add code to handle this!");
456 const uint32_t unwind_reg_kind
= m_unwind_plan_ptr
->GetRegisterKind();
457 reg_num
= context
.info
.RegisterToRegisterPlusOffset
.data_reg
458 .kinds
[unwind_reg_kind
];
459 generic_regnum
= context
.info
.RegisterToRegisterPlusOffset
.data_reg
460 .kinds
[eRegisterKindGeneric
];
462 if (reg_num
!= LLDB_INVALID_REGNUM
&&
463 generic_regnum
!= LLDB_REGNUM_GENERIC_SP
) {
464 if (m_pushed_regs
.try_emplace(reg_num
, addr
).second
) {
465 const int32_t offset
= addr
- m_initial_sp
;
466 m_curr_row
->SetRegisterLocationToAtCFAPlusOffset(reg_num
, offset
,
467 /*can_replace=*/true);
468 m_curr_row_modified
= true;
477 bool UnwindAssemblyInstEmulation::ReadRegister(EmulateInstruction
*instruction
,
479 const RegisterInfo
*reg_info
,
480 RegisterValue
®_value
) {
482 if (baton
&& reg_info
)
483 return ((UnwindAssemblyInstEmulation
*)baton
)
484 ->ReadRegister(instruction
, reg_info
, reg_value
);
487 bool UnwindAssemblyInstEmulation::ReadRegister(EmulateInstruction
*instruction
,
488 const RegisterInfo
*reg_info
,
489 RegisterValue
®_value
) {
490 bool synthetic
= GetRegisterValue(*reg_info
, reg_value
);
492 Log
*log
= GetLog(LLDBLog::Unwind
);
494 if (log
&& log
->GetVerbose()) {
497 strm
.Printf("UnwindAssemblyInstEmulation::ReadRegister (name = \"%s\") => "
498 "synthetic_value = %i, value = ",
499 reg_info
->name
, synthetic
);
500 DumpRegisterValue(reg_value
, strm
, *reg_info
, false, false, eFormatDefault
);
501 log
->PutString(strm
.GetString());
506 bool UnwindAssemblyInstEmulation::WriteRegister(
507 EmulateInstruction
*instruction
, void *baton
,
508 const EmulateInstruction::Context
&context
, const RegisterInfo
*reg_info
,
509 const RegisterValue
®_value
) {
510 if (baton
&& reg_info
)
511 return ((UnwindAssemblyInstEmulation
*)baton
)
512 ->WriteRegister(instruction
, context
, reg_info
, reg_value
);
515 bool UnwindAssemblyInstEmulation::WriteRegister(
516 EmulateInstruction
*instruction
, const EmulateInstruction::Context
&context
,
517 const RegisterInfo
*reg_info
, const RegisterValue
®_value
) {
518 Log
*log
= GetLog(LLDBLog::Unwind
);
520 if (log
&& log
->GetVerbose()) {
524 "UnwindAssemblyInstEmulation::WriteRegister (name = \"%s\", value = ",
526 DumpRegisterValue(reg_value
, strm
, *reg_info
, false, false, eFormatDefault
);
527 strm
.PutCString(", context = ");
528 context
.Dump(strm
, instruction
);
529 log
->PutString(strm
.GetString());
532 SetRegisterValue(*reg_info
, reg_value
);
534 switch (context
.type
) {
535 case EmulateInstruction::eContextInvalid
:
536 case EmulateInstruction::eContextReadOpcode
:
537 case EmulateInstruction::eContextImmediate
:
538 case EmulateInstruction::eContextAdjustBaseRegister
:
539 case EmulateInstruction::eContextRegisterPlusOffset
:
540 case EmulateInstruction::eContextAdjustPC
:
541 case EmulateInstruction::eContextRegisterStore
:
542 case EmulateInstruction::eContextSupervisorCall
:
543 case EmulateInstruction::eContextTableBranchReadMemory
:
544 case EmulateInstruction::eContextWriteRegisterRandomBits
:
545 case EmulateInstruction::eContextWriteMemoryRandomBits
:
546 case EmulateInstruction::eContextAdvancePC
:
547 case EmulateInstruction::eContextReturnFromException
:
548 case EmulateInstruction::eContextPushRegisterOnStack
:
549 case EmulateInstruction::eContextRegisterLoad
:
551 // const uint32_t reg_num =
552 // reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
553 // if (reg_num != LLDB_INVALID_REGNUM)
555 // const bool can_replace_only_if_unspecified = true;
557 // m_curr_row.SetRegisterLocationToUndefined (reg_num,
558 // can_replace_only_if_unspecified,
559 // can_replace_only_if_unspecified);
560 // m_curr_row_modified = true;
565 case EmulateInstruction::eContextArithmetic
: {
566 // If we adjusted the current frame pointer by a constant then adjust the
568 // with the same amount.
569 lldb::RegisterKind kind
= m_unwind_plan_ptr
->GetRegisterKind();
570 if (m_fp_is_cfa
&& reg_info
->kinds
[kind
] == m_cfa_reg_info
.kinds
[kind
] &&
571 context
.GetInfoType() ==
572 EmulateInstruction::eInfoTypeRegisterPlusOffset
&&
573 context
.info
.RegisterPlusOffset
.reg
.kinds
[kind
] ==
574 m_cfa_reg_info
.kinds
[kind
]) {
575 const int64_t offset
= context
.info
.RegisterPlusOffset
.signed_offset
;
576 m_curr_row
->GetCFAValue().IncOffset(-1 * offset
);
577 m_curr_row_modified
= true;
581 case EmulateInstruction::eContextAbsoluteBranchRegister
:
582 case EmulateInstruction::eContextRelativeBranchImmediate
: {
583 if (context
.GetInfoType() == EmulateInstruction::eInfoTypeISAAndImmediate
&&
584 context
.info
.ISAAndImmediate
.unsigned_data32
> 0) {
585 m_forward_branch_offset
=
586 context
.info
.ISAAndImmediateSigned
.signed_data32
;
587 } else if (context
.GetInfoType() ==
588 EmulateInstruction::eInfoTypeISAAndImmediateSigned
&&
589 context
.info
.ISAAndImmediateSigned
.signed_data32
> 0) {
590 m_forward_branch_offset
= context
.info
.ISAAndImmediate
.unsigned_data32
;
591 } else if (context
.GetInfoType() ==
592 EmulateInstruction::eInfoTypeImmediate
&&
593 context
.info
.unsigned_immediate
> 0) {
594 m_forward_branch_offset
= context
.info
.unsigned_immediate
;
595 } else if (context
.GetInfoType() ==
596 EmulateInstruction::eInfoTypeImmediateSigned
&&
597 context
.info
.signed_immediate
> 0) {
598 m_forward_branch_offset
= context
.info
.signed_immediate
;
602 case EmulateInstruction::eContextPopRegisterOffStack
: {
603 const uint32_t reg_num
=
604 reg_info
->kinds
[m_unwind_plan_ptr
->GetRegisterKind()];
605 const uint32_t generic_regnum
= reg_info
->kinds
[eRegisterKindGeneric
];
606 if (reg_num
!= LLDB_INVALID_REGNUM
&&
607 generic_regnum
!= LLDB_REGNUM_GENERIC_SP
) {
608 switch (context
.GetInfoType()) {
609 case EmulateInstruction::eInfoTypeAddress
:
610 if (auto it
= m_pushed_regs
.find(reg_num
);
611 it
!= m_pushed_regs
.end() && context
.info
.address
== it
->second
) {
612 m_curr_row
->SetRegisterLocationToSame(reg_num
,
613 false /*must_replace*/);
614 m_curr_row_modified
= true;
616 // FP has been restored to its original value, we are back
617 // to using SP to calculate the CFA.
620 lldb::RegisterKind sp_reg_kind
= eRegisterKindGeneric
;
621 uint32_t sp_reg_num
= LLDB_REGNUM_GENERIC_SP
;
622 RegisterInfo sp_reg_info
=
623 *m_inst_emulator_up
->GetRegisterInfo(sp_reg_kind
, sp_reg_num
);
624 RegisterValue sp_reg_val
;
625 if (GetRegisterValue(sp_reg_info
, sp_reg_val
)) {
626 m_cfa_reg_info
= sp_reg_info
;
627 const uint32_t cfa_reg_num
=
628 sp_reg_info
.kinds
[m_unwind_plan_ptr
->GetRegisterKind()];
629 assert(cfa_reg_num
!= LLDB_INVALID_REGNUM
);
630 m_curr_row
->GetCFAValue().SetIsRegisterPlusOffset(
631 cfa_reg_num
, m_initial_sp
- sp_reg_val
.GetAsUInt64());
636 case EmulateInstruction::eInfoTypeISA
:
638 (generic_regnum
== LLDB_REGNUM_GENERIC_PC
||
639 generic_regnum
== LLDB_REGNUM_GENERIC_FLAGS
) &&
640 "eInfoTypeISA used for popping a register other the PC/FLAGS");
641 if (generic_regnum
!= LLDB_REGNUM_GENERIC_FLAGS
) {
642 m_curr_row
->SetRegisterLocationToSame(reg_num
,
643 false /*must_replace*/);
644 m_curr_row_modified
= true;
648 assert(false && "unhandled case, add code to handle this!");
654 case EmulateInstruction::eContextSetFramePointer
:
657 m_cfa_reg_info
= *reg_info
;
658 const uint32_t cfa_reg_num
=
659 reg_info
->kinds
[m_unwind_plan_ptr
->GetRegisterKind()];
660 assert(cfa_reg_num
!= LLDB_INVALID_REGNUM
);
661 m_curr_row
->GetCFAValue().SetIsRegisterPlusOffset(
662 cfa_reg_num
, m_initial_sp
- reg_value
.GetAsUInt64());
663 m_curr_row_modified
= true;
667 case EmulateInstruction::eContextRestoreStackPointer
:
670 m_cfa_reg_info
= *reg_info
;
671 const uint32_t cfa_reg_num
=
672 reg_info
->kinds
[m_unwind_plan_ptr
->GetRegisterKind()];
673 assert(cfa_reg_num
!= LLDB_INVALID_REGNUM
);
674 m_curr_row
->GetCFAValue().SetIsRegisterPlusOffset(
675 cfa_reg_num
, m_initial_sp
- reg_value
.GetAsUInt64());
676 m_curr_row_modified
= true;
680 case EmulateInstruction::eContextAdjustStackPointer
:
681 // If we have created a frame using the frame pointer, don't follow
682 // subsequent adjustments to the stack pointer.
684 m_curr_row
->GetCFAValue().SetIsRegisterPlusOffset(
685 m_curr_row
->GetCFAValue().GetRegisterNumber(),
686 m_initial_sp
- reg_value
.GetAsUInt64());
687 m_curr_row_modified
= true;