Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/lldb/source/Plugins/UnwindAssembly/InstEmulation/UnwindAssemblyInstEmulation.cpp
39644 views
1
//===-- UnwindAssemblyInstEmulation.cpp -----------------------------------===//
2
//
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
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "UnwindAssemblyInstEmulation.h"
10
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"
28
29
using namespace lldb;
30
using namespace lldb_private;
31
32
LLDB_PLUGIN_DEFINE(UnwindAssemblyInstEmulation)
33
34
// UnwindAssemblyInstEmulation method definitions
35
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());
40
if (process_sp) {
41
Status error;
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()) {
46
return false;
47
}
48
}
49
return GetNonCallSiteUnwindPlanFromAssembly(
50
range, function_text.data(), function_text.size(), unwind_plan);
51
}
52
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)
57
return false;
58
59
if (range.GetByteSize() > 0 && range.GetBaseAddress().IsValid() &&
60
m_inst_emulator_up.get()) {
61
62
// The instruction emulation subclass setup the unwind plan for the first
63
// instruction.
64
m_inst_emulator_up->CreateFunctionEntryUnwind(unwind_plan);
65
66
// CreateFunctionEntryUnwind should have created the first row. If it
67
// doesn't, then we are done.
68
if (unwind_plan.GetRowCount() == 0)
69
return false;
70
71
const bool prefer_file_cache = true;
72
DisassemblerSP disasm_sp(Disassembler::DisassembleBytes(
73
m_arch, nullptr, nullptr, range.GetBaseAddress(), opcode_data,
74
opcode_size, 99999, prefer_file_cache));
75
76
Log *log = GetLog(LLDBLog::Unwind);
77
78
if (disasm_sp) {
79
80
m_range_ptr = &range;
81
m_unwind_plan_ptr = &unwind_plan;
82
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());
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 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);
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
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
113
// function.
114
std::map<lldb::addr_t, std::pair<UnwindPlan::RowSP, RegisterValueMap>>
115
saved_unwind_states;
116
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;
121
if (last_row.get())
122
*newrow = *last_row.get();
123
m_curr_row.reset(newrow);
124
125
// Add the initial state to the save list with offset 0.
126
saved_unwind_states.insert({0, {last_row, m_register_values}});
127
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);
133
134
// The architecture dependent condition code of the last processed
135
// instruction.
136
EmulateInstruction::InstructionCondition last_condition =
137
EmulateInstruction::UnconditionalCondition;
138
lldb::addr_t condition_block_start_offset = 0;
139
140
for (size_t idx = 0; idx < num_instructions; ++idx) {
141
m_curr_row_modified = false;
142
m_forward_branch_offset = 0;
143
144
inst = inst_list.GetInstructionAtIndex(idx).get();
145
if (inst) {
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
152
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
157
// instruction.
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
164
// new m_curr_row.
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);
174
// set m_fp_is_cfa.
175
if (sp_reg_info.kinds[row_kind] == row_cfa_regnum)
176
m_fp_is_cfa = false;
177
else
178
m_fp_is_cfa = true;
179
}
180
}
181
182
m_inst_emulator_up->SetInstruction(inst->GetOpcode(),
183
inst->GetAddress(), nullptr);
184
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.
193
auto new_row =
194
std::make_shared<UnwindPlan::Row>(*m_curr_row.get());
195
saved_unwind_states.insert(
196
{current_offset, {new_row, m_register_values}});
197
}
198
199
// If the last instruction was conditional with a different
200
// condition then the then current condition then restore the
201
// condition.
202
if (last_condition !=
203
EmulateInstruction::UnconditionalCondition) {
204
const auto &saved_state =
205
saved_unwind_states.at(condition_block_start_offset);
206
m_curr_row =
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
211
// new m_curr_row.
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);
221
// set m_fp_is_cfa.
222
if (sp_reg_info.kinds[row_kind] == row_cfa_regnum)
223
m_fp_is_cfa = false;
224
else
225
m_fp_is_cfa = true;
226
}
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),
233
replace_existing);
234
}
235
236
// We are starting a new conditional block at the actual offset
237
condition_block_start_offset = current_offset;
238
}
239
240
if (log && log->GetVerbose()) {
241
StreamString strm;
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());
248
}
249
250
last_condition = m_inst_emulator_up->GetInstructionCondition();
251
252
m_inst_emulator_up->EvaluateInstruction(
253
eEmulateInstructionOptionIgnoreConditions);
254
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)) {
260
auto newrow =
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);
267
}
268
269
// Were there any changes to the CFI while evaluating this
270
// instruction?
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}});
282
283
// Allocate a new Row for m_curr_row, copy the current state
284
// into it
285
UnwindPlan::Row *newrow = new UnwindPlan::Row;
286
*newrow = *m_curr_row.get();
287
m_curr_row.reset(newrow);
288
}
289
}
290
}
291
}
292
}
293
}
294
295
if (log && log->GetVerbose()) {
296
StreamString strm;
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());
302
}
303
return unwind_plan.GetRowCount() > 0;
304
}
305
return false;
306
}
307
308
bool UnwindAssemblyInstEmulation::AugmentUnwindPlanFromCallSite(
309
AddressRange &func, Thread &thread, UnwindPlan &unwind_plan) {
310
return false;
311
}
312
313
bool UnwindAssemblyInstEmulation::GetFastUnwindPlan(AddressRange &func,
314
Thread &thread,
315
UnwindPlan &unwind_plan) {
316
return false;
317
}
318
319
bool UnwindAssemblyInstEmulation::FirstNonPrologueInsn(
320
AddressRange &func, const ExecutionContext &exe_ctx,
321
Address &first_non_prologue_insn) {
322
return false;
323
}
324
325
UnwindAssembly *
326
UnwindAssemblyInstEmulation::CreateInstance(const ArchSpec &arch) {
327
std::unique_ptr<EmulateInstruction> inst_emulator_up(
328
EmulateInstruction::FindPlugin(arch, eInstructionTypePrologueEpilogue,
329
nullptr));
330
// Make sure that all prologue instructions are handled
331
if (inst_emulator_up)
332
return new UnwindAssemblyInstEmulation(arch, inst_emulator_up.release());
333
return nullptr;
334
}
335
336
void UnwindAssemblyInstEmulation::Initialize() {
337
PluginManager::RegisterPlugin(GetPluginNameStatic(),
338
GetPluginDescriptionStatic(), CreateInstance);
339
}
340
341
void UnwindAssemblyInstEmulation::Terminate() {
342
PluginManager::UnregisterPlugin(CreateInstance);
343
}
344
345
llvm::StringRef UnwindAssemblyInstEmulation::GetPluginDescriptionStatic() {
346
return "Instruction emulation based unwind information.";
347
}
348
349
uint64_t UnwindAssemblyInstEmulation::MakeRegisterKindValuePair(
350
const RegisterInfo &reg_info) {
351
lldb::RegisterKind reg_kind;
352
uint32_t reg_num;
353
if (EmulateInstruction::GetBestRegisterKindAndNumber(&reg_info, reg_kind,
354
reg_num))
355
return (uint64_t)reg_kind << 24 | reg_num;
356
return 0ull;
357
}
358
359
void UnwindAssemblyInstEmulation::SetRegisterValue(
360
const RegisterInfo &reg_info, const RegisterValue &reg_value) {
361
m_register_values[MakeRegisterKindValuePair(reg_info)] = reg_value;
362
}
363
364
bool UnwindAssemblyInstEmulation::GetRegisterValue(const RegisterInfo &reg_info,
365
RegisterValue &reg_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
371
// to it...
372
}
373
// We are making up a value that is recognizable...
374
reg_value.SetUInt(reg_id, reg_info.byte_size);
375
return false;
376
}
377
378
size_t UnwindAssemblyInstEmulation::ReadMemory(
379
EmulateInstruction *instruction, void *baton,
380
const EmulateInstruction::Context &context, lldb::addr_t addr, void *dst,
381
size_t dst_len) {
382
Log *log = GetLog(LLDBLog::Unwind);
383
384
if (log && log->GetVerbose()) {
385
StreamString strm;
386
strm.Printf(
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());
392
}
393
memset(dst, 0, dst_len);
394
return dst_len;
395
}
396
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);
404
return 0;
405
}
406
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());
413
414
Log *log = GetLog(LLDBLog::Unwind);
415
416
if (log && log->GetVerbose()) {
417
StreamString strm;
418
419
strm.PutCString("UnwindAssemblyInstEmulation::WriteMemory (");
420
DumpDataExtractor(data, &strm, 0, eFormatBytes, 1, dst_len, UINT32_MAX,
421
addr, 0, 0);
422
strm.PutCString(", context = ");
423
context.Dump(strm, instruction);
424
log->PutString(strm.GetString());
425
}
426
427
switch (context.type) {
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
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];
461
462
if (reg_num != LLDB_INVALID_REGNUM &&
463
generic_regnum != LLDB_REGNUM_GENERIC_SP) {
464
if (m_pushed_regs.find(reg_num) == m_pushed_regs.end()) {
465
m_pushed_regs[reg_num] = addr;
466
const int32_t offset = addr - m_initial_sp;
467
m_curr_row->SetRegisterLocationToAtCFAPlusOffset(reg_num, offset,
468
/*can_replace=*/true);
469
m_curr_row_modified = true;
470
}
471
}
472
} break;
473
}
474
475
return dst_len;
476
}
477
478
bool UnwindAssemblyInstEmulation::ReadRegister(EmulateInstruction *instruction,
479
void *baton,
480
const RegisterInfo *reg_info,
481
RegisterValue &reg_value) {
482
483
if (baton && reg_info)
484
return ((UnwindAssemblyInstEmulation *)baton)
485
->ReadRegister(instruction, reg_info, reg_value);
486
return false;
487
}
488
bool UnwindAssemblyInstEmulation::ReadRegister(EmulateInstruction *instruction,
489
const RegisterInfo *reg_info,
490
RegisterValue &reg_value) {
491
bool synthetic = GetRegisterValue(*reg_info, reg_value);
492
493
Log *log = GetLog(LLDBLog::Unwind);
494
495
if (log && log->GetVerbose()) {
496
497
StreamString strm;
498
strm.Printf("UnwindAssemblyInstEmulation::ReadRegister (name = \"%s\") => "
499
"synthetic_value = %i, value = ",
500
reg_info->name, synthetic);
501
DumpRegisterValue(reg_value, strm, *reg_info, false, false, eFormatDefault);
502
log->PutString(strm.GetString());
503
}
504
return true;
505
}
506
507
bool UnwindAssemblyInstEmulation::WriteRegister(
508
EmulateInstruction *instruction, void *baton,
509
const EmulateInstruction::Context &context, const RegisterInfo *reg_info,
510
const RegisterValue &reg_value) {
511
if (baton && reg_info)
512
return ((UnwindAssemblyInstEmulation *)baton)
513
->WriteRegister(instruction, context, reg_info, reg_value);
514
return false;
515
}
516
bool UnwindAssemblyInstEmulation::WriteRegister(
517
EmulateInstruction *instruction, const EmulateInstruction::Context &context,
518
const RegisterInfo *reg_info, const RegisterValue &reg_value) {
519
Log *log = GetLog(LLDBLog::Unwind);
520
521
if (log && log->GetVerbose()) {
522
523
StreamString strm;
524
strm.Printf(
525
"UnwindAssemblyInstEmulation::WriteRegister (name = \"%s\", value = ",
526
reg_info->name);
527
DumpRegisterValue(reg_value, strm, *reg_info, false, false, eFormatDefault);
528
strm.PutCString(", context = ");
529
context.Dump(strm, instruction);
530
log->PutString(strm.GetString());
531
}
532
533
SetRegisterValue(*reg_info, reg_value);
534
535
switch (context.type) {
536
case EmulateInstruction::eContextInvalid:
537
case EmulateInstruction::eContextReadOpcode:
538
case EmulateInstruction::eContextImmediate:
539
case EmulateInstruction::eContextAdjustBaseRegister:
540
case EmulateInstruction::eContextRegisterPlusOffset:
541
case EmulateInstruction::eContextAdjustPC:
542
case EmulateInstruction::eContextRegisterStore:
543
case EmulateInstruction::eContextSupervisorCall:
544
case EmulateInstruction::eContextTableBranchReadMemory:
545
case EmulateInstruction::eContextWriteRegisterRandomBits:
546
case EmulateInstruction::eContextWriteMemoryRandomBits:
547
case EmulateInstruction::eContextAdvancePC:
548
case EmulateInstruction::eContextReturnFromException:
549
case EmulateInstruction::eContextPushRegisterOnStack:
550
case EmulateInstruction::eContextRegisterLoad:
551
// {
552
// const uint32_t reg_num =
553
// reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
554
// if (reg_num != LLDB_INVALID_REGNUM)
555
// {
556
// const bool can_replace_only_if_unspecified = true;
557
//
558
// m_curr_row.SetRegisterLocationToUndefined (reg_num,
559
// can_replace_only_if_unspecified,
560
// can_replace_only_if_unspecified);
561
// m_curr_row_modified = true;
562
// }
563
// }
564
break;
565
566
case EmulateInstruction::eContextArithmetic: {
567
// If we adjusted the current frame pointer by a constant then adjust the
568
// CFA offset
569
// with the same amount.
570
lldb::RegisterKind kind = m_unwind_plan_ptr->GetRegisterKind();
571
if (m_fp_is_cfa && reg_info->kinds[kind] == m_cfa_reg_info.kinds[kind] &&
572
context.GetInfoType() ==
573
EmulateInstruction::eInfoTypeRegisterPlusOffset &&
574
context.info.RegisterPlusOffset.reg.kinds[kind] ==
575
m_cfa_reg_info.kinds[kind]) {
576
const int64_t offset = context.info.RegisterPlusOffset.signed_offset;
577
m_curr_row->GetCFAValue().IncOffset(-1 * offset);
578
m_curr_row_modified = true;
579
}
580
} break;
581
582
case EmulateInstruction::eContextAbsoluteBranchRegister:
583
case EmulateInstruction::eContextRelativeBranchImmediate: {
584
if (context.GetInfoType() == EmulateInstruction::eInfoTypeISAAndImmediate &&
585
context.info.ISAAndImmediate.unsigned_data32 > 0) {
586
m_forward_branch_offset =
587
context.info.ISAAndImmediateSigned.signed_data32;
588
} else if (context.GetInfoType() ==
589
EmulateInstruction::eInfoTypeISAAndImmediateSigned &&
590
context.info.ISAAndImmediateSigned.signed_data32 > 0) {
591
m_forward_branch_offset = context.info.ISAAndImmediate.unsigned_data32;
592
} else if (context.GetInfoType() ==
593
EmulateInstruction::eInfoTypeImmediate &&
594
context.info.unsigned_immediate > 0) {
595
m_forward_branch_offset = context.info.unsigned_immediate;
596
} else if (context.GetInfoType() ==
597
EmulateInstruction::eInfoTypeImmediateSigned &&
598
context.info.signed_immediate > 0) {
599
m_forward_branch_offset = context.info.signed_immediate;
600
}
601
} break;
602
603
case EmulateInstruction::eContextPopRegisterOffStack: {
604
const uint32_t reg_num =
605
reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
606
const uint32_t generic_regnum = reg_info->kinds[eRegisterKindGeneric];
607
if (reg_num != LLDB_INVALID_REGNUM &&
608
generic_regnum != LLDB_REGNUM_GENERIC_SP) {
609
switch (context.GetInfoType()) {
610
case EmulateInstruction::eInfoTypeAddress:
611
if (m_pushed_regs.find(reg_num) != m_pushed_regs.end() &&
612
context.info.address == m_pushed_regs[reg_num]) {
613
m_curr_row->SetRegisterLocationToSame(reg_num,
614
false /*must_replace*/);
615
m_curr_row_modified = true;
616
617
// FP has been restored to its original value, we are back
618
// to using SP to calculate the CFA.
619
if (m_fp_is_cfa) {
620
m_fp_is_cfa = false;
621
lldb::RegisterKind sp_reg_kind = eRegisterKindGeneric;
622
uint32_t sp_reg_num = LLDB_REGNUM_GENERIC_SP;
623
RegisterInfo sp_reg_info =
624
*m_inst_emulator_up->GetRegisterInfo(sp_reg_kind, sp_reg_num);
625
RegisterValue sp_reg_val;
626
if (GetRegisterValue(sp_reg_info, sp_reg_val)) {
627
m_cfa_reg_info = sp_reg_info;
628
const uint32_t cfa_reg_num =
629
sp_reg_info.kinds[m_unwind_plan_ptr->GetRegisterKind()];
630
assert(cfa_reg_num != LLDB_INVALID_REGNUM);
631
m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(
632
cfa_reg_num, m_initial_sp - sp_reg_val.GetAsUInt64());
633
}
634
}
635
}
636
break;
637
case EmulateInstruction::eInfoTypeISA:
638
assert(
639
(generic_regnum == LLDB_REGNUM_GENERIC_PC ||
640
generic_regnum == LLDB_REGNUM_GENERIC_FLAGS) &&
641
"eInfoTypeISA used for popping a register other the PC/FLAGS");
642
if (generic_regnum != LLDB_REGNUM_GENERIC_FLAGS) {
643
m_curr_row->SetRegisterLocationToSame(reg_num,
644
false /*must_replace*/);
645
m_curr_row_modified = true;
646
}
647
break;
648
default:
649
assert(false && "unhandled case, add code to handle this!");
650
break;
651
}
652
}
653
} break;
654
655
case EmulateInstruction::eContextSetFramePointer:
656
if (!m_fp_is_cfa) {
657
m_fp_is_cfa = true;
658
m_cfa_reg_info = *reg_info;
659
const uint32_t cfa_reg_num =
660
reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
661
assert(cfa_reg_num != LLDB_INVALID_REGNUM);
662
m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(
663
cfa_reg_num, m_initial_sp - reg_value.GetAsUInt64());
664
m_curr_row_modified = true;
665
}
666
break;
667
668
case EmulateInstruction::eContextRestoreStackPointer:
669
if (m_fp_is_cfa) {
670
m_fp_is_cfa = false;
671
m_cfa_reg_info = *reg_info;
672
const uint32_t cfa_reg_num =
673
reg_info->kinds[m_unwind_plan_ptr->GetRegisterKind()];
674
assert(cfa_reg_num != LLDB_INVALID_REGNUM);
675
m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(
676
cfa_reg_num, m_initial_sp - reg_value.GetAsUInt64());
677
m_curr_row_modified = true;
678
}
679
break;
680
681
case EmulateInstruction::eContextAdjustStackPointer:
682
// If we have created a frame using the frame pointer, don't follow
683
// subsequent adjustments to the stack pointer.
684
if (!m_fp_is_cfa) {
685
m_curr_row->GetCFAValue().SetIsRegisterPlusOffset(
686
m_curr_row->GetCFAValue().GetRegisterNumber(),
687
m_initial_sp - reg_value.GetAsUInt64());
688
m_curr_row_modified = true;
689
}
690
break;
691
}
692
return true;
693
}
694
695